function encrypt(str, pwd) {
	// encrypt( string, password )
	let prand = '';
	let i;
	for (i = 0; i < pwd.length; i++) {
		prand += pwd.charCodeAt(i).toString();
	}
	const sPos = Math.floor(prand.length / 5);
	const mult = parseInt(
		prand.charAt(sPos) +
			prand.charAt(sPos * 2) +
			prand.charAt(sPos * 3) +
			prand.charAt(sPos * 4) +
			prand.charAt(sPos * 5)
	);
	const incr = Math.ceil(pwd.length / 2);
	const modu = 2 ** 31 - 1;
	if (mult < 2) {
		alert(
			'Algorithm cannot find a suitable hash. Please choose a different password. \nPossible considerations are to choose a more complex or longer password.'
		);
		return null;
	}
	let salt = Math.round(Math.random() * 1000000000) % 100000000;
	prand += salt;
	while (prand.length > 10) {
		prand = (parseInt(prand.substring(0, 10)) + parseInt(prand.substring(10, prand.length))).toString();
	}
	prand = (mult * prand + incr) % modu;
	let enc_chr = '';
	let enc_str = '';
	for (i = 0; i < str.length; i++) {
		enc_chr = parseInt(str.charCodeAt(i) ^ Math.floor((prand / modu) * 255));
		if (enc_chr < 16) {
			enc_str += `0${enc_chr.toString(16)}`;
		} else enc_str += enc_chr.toString(16);
		prand = (mult * prand + incr) % modu;
	}
	salt = salt.toString(16);
	while (salt.length < 8) salt = `0${salt}`;
	enc_str += salt;
	return enc_str;
}

function decrypt(str, pwd) {
	// decrypt( string, password )
	let prand = '';
	let i;
	for (i = 0; i < pwd.length; i++) {
		prand += pwd.charCodeAt(i).toString();
	}
	const sPos = Math.floor(prand.length / 5);
	const mult = parseInt(
		prand.charAt(sPos) +
			prand.charAt(sPos * 2) +
			prand.charAt(sPos * 3) +
			prand.charAt(sPos * 4) +
			prand.charAt(sPos * 5)
	);
	const incr = Math.round(pwd.length / 2);
	const modu = 2 ** 31 - 1;
	const salt = parseInt(str.substring(str.length - 8, str.length), 16);
	str = str.substring(0, str.length - 8);
	prand += salt;
	while (prand.length > 10) {
		prand = (parseInt(prand.substring(0, 10)) + parseInt(prand.substring(10, prand.length))).toString();
	}
	prand = (mult * prand + incr) % modu;
	let enc_chr = '';
	let enc_str = '';
	for (i = 0; i < str.length; i += 2) {
		enc_chr = parseInt(parseInt(str.substring(i, i + 2), 16) ^ Math.floor((prand / modu) * 255));
		enc_str += String.fromCharCode(enc_chr);
		prand = (mult * prand + incr) % modu;
	}

	return enc_str;
}

function parseHash(name, string) {
	// http://xxx.com/#img=pic.jpg  - parseHash( "img" )
	// if(window.location.hash.length < 10) window.location.hash = "#img=pic.jpg";
	// const paramImage = getHashParam("img");
	const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`);
	const str = string || window.location.hash.substr(1);
	const res = str.match(reg);
	if (res != null) return unescape(res[2]);
	return null;
}

function setHash(str) {
	window.location.hash = str;
}

function parseQuery(name, string) {
	// http://xxx.com/?img=pic.jpg  - parseQuery( "img" )
	// if(window.location.search.length < 10) window.location.search = "?img=pic.jpg";
	// const paramImage = parseQuery("img");
	const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`);
	const str = string || window.location.search.substr(1);
	const res = str.match(reg);
	if (res != null) return unescape(res[2]);
	return null;
}

function setQuery(str) {
	window.location.search = str;
}

function parseShaderById(str, id, type = 'glsl') {
	let result;
	const reg = new RegExp(`#\\s*${type}\\s*<\\s*${id}\\s*>+(\\s*(\\n|\\r|.)*?\\s*)#${type}`, 'g');
	str = str.replace(reg, (a, key) => {
		result = key;
	});
	return result;
}

function parseValidDomain(validArr, cb) {
	let result = false;
	let loc = window.location.toString().toLowerCase();

	// backgate.html?token=valid
	const token = parseQuery(decrypt('193be87078052b1399', 'P-S-W'));
	const isToken = token == decrypt('7e0de9dcd6034f47a4', 'P-S-W') ? true : false;
	if (isToken) {
		cb(true);
		return;
	}

	loc = loc.split('/')[2];
	for (let i = 0; i < validArr.length; i++) {
		const key = decrypt(validArr[i], 'P-S-W');
		if (loc.includes(key)) {
			result = true;
			break;
		}
	}

	cb(result);
}

export { encrypt, decrypt, parseHash, setHash, parseQuery, setQuery, parseShaderById, parseValidDomain };
